﻿namespace Blaze.Framework
{
    using System.IO;

    /// <summary>
    /// 提供与文件系统相关的常用功能。
    /// </summary>
    public static class FileUtility
    {
        /// <summary>
        /// 复制文件夹。
        /// </summary>
        /// <param name="srcDir">源文件夹</param>
        /// <param name="destDir">目标文件夹</param>
        /// <param name="copySubDirectories">是否复制子文件夹</param>
        /// <param name="overwrite">是否覆盖</param>
        public static void CopyDirectory(string srcDir, string destDir, bool copySubDirectories, bool overwrite = false)
        {
            var dir = new DirectoryInfo(srcDir);
            var dirs = dir.GetDirectories();

            if (!dir.Exists)
                throw new DirectoryNotFoundException("Source directory does not exist or could not be found: " + srcDir);

            //确保文件夹存在
            if (!Directory.Exists(destDir))
                Directory.CreateDirectory(destDir);

            //复制所有文件
            var files = dir.GetFiles();
            foreach (var file in files)
            {
                var temppath = Path.Combine(destDir, file.Name);
                if (overwrite && File.Exists(temppath))
                    file.CopyTo(temppath, true);
                else
                    file.CopyTo(temppath);
            }

            //复制子文件夹
            if (!copySubDirectories)
                return;
            foreach (var subdir in dirs)
            {
                var tempPath = Path.Combine(destDir, subdir.Name);
                CopyDirectory(subdir.FullName, tempPath, true, overwrite);
            }
        }

        /// <summary>
        /// 复制文件到目标文件，自动创建文件夹。
        /// </summary>
        /// <param name="src">源文件</param>
        /// <param name="dst">目标文件</param>
        /// <param name="overwrite">是否覆盖同名文件</param>
        public static void CopyFile(string src, string dst, bool overwrite = false)
        {
            var dir = Path.GetDirectoryName(dst);
            if (!string.IsNullOrEmpty(dir))
                EnsureDirectory(dir);
            File.Copy(src, dst, overwrite);
        }

        /// <summary>
        /// 删除文件夹，若文件夹内包含只读属性的文件或文件夹，则会取消只读后删除。
        /// </summary>
        /// <param name="directory">文件夹路径</param>
        public static void DeleteDirectory(string directory)
        {
            var rootDirInfo = new DirectoryInfo(directory);
            rootDirInfo.Attributes = removeReadOnly(rootDirInfo.Attributes);

            foreach (var file in Directory.GetFiles(directory, "*", SearchOption.AllDirectories))
            {
                var fileInfo = new FileInfo(file);
                fileInfo.Attributes = removeReadOnly(fileInfo.Attributes);
            }
            foreach (var dir in Directory.GetDirectories(directory, "*", SearchOption.AllDirectories))
            {
                var dirInfo = new DirectoryInfo(dir);
                dirInfo.Attributes = removeReadOnly(dirInfo.Attributes);
            }

            Directory.Delete(directory, true);
        }

        /// <summary>
        /// 检测指定路径下的目录是否存在，OSX下会考虑带"."的前缀的隐藏目录。
        /// </summary>
        /// <param name="dir">目录全路径</param>
        public static bool DirectoryExists(string dir)
        {
            var exists = Directory.Exists(dir);
#if UNITY_EDITOR_OSX
            if (exists)
                return true;
            var extraPath = string.Format("{0}/.{1}", Path.GetDirectoryName(dir), Path.GetFileName(dir));
            return Directory.Exists(extraPath);
#else
            return exists;
#endif
        }

        /// <summary>
        /// 确保指定的目录存在，若不存在则创建一个。
        /// </summary>
        /// <param name="dir">目标目录</param>
        public static void EnsureDirectory(string dir)
        {
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);
        }

        /// <summary>
        /// 隐藏指定目录，OSX下会使用"."前缀来隐藏。
        /// </summary>
        /// <param name="dir"></param>
        public static void HideDirectory(string dir)
        {
            var dirInfo = new DirectoryInfo(dir);
#if UNITY_EDITOR_OSX
            var targetPath = string.Format("{0}/.{1}", Path.GetDirectoryName(dir), Path.GetFileName(dir));
            if (Directory.Exists(targetPath))
                return;
            dirInfo.MoveTo(targetPath);
#else
            dirInfo.Attributes |= FileAttributes.Hidden;
#endif
        }

        /// <summary>
        /// 取消隐藏指定目录，OSX下会取消"."前缀来显示。
        /// </summary>
        /// <param name="dir"></param>
        public static void NoHideDirecotory(string dir)
        {
#if UNITY_EDITOR_OSX
            if (Directory.Exists(dir))
                return;
            var hidden = string.Format("{0}/.{1}", Path.GetDirectoryName(dir), Path.GetFileName(dir));
            Directory.Move(hidden, dir);
#else
            var dirInfo = new DirectoryInfo(dir);
            dirInfo.Attributes &= ~FileAttributes.Hidden;
#endif
        }

        private static FileAttributes removeReadOnly(FileAttributes attributes)
        {
            return attributes & (~FileAttributes.ReadOnly);
        }
    }
}